package com.atguigu.java2;

import com.atguigu.java1.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author : leimingchao
 * @Description: 调用运行时类中指定的结构:属性，方法，构造器
 * @date Date : 2021年06月13日 19:52
 */
public class ReflectionTest {

    @Test
    public void test() throws Exception {
        Class clazz = Person.class;
        //创建运行时类对象
        Person person = (Person) clazz.newInstance();
        //获取指定的属性,要求运行时类的属性声明为public，通常不采用此方法
        Field id = clazz.getField("id");

        //设置当前属性的值
        /**
         * set():
         *      参数一：指明设置哪个对象的属性
         *      参数二：将此属性值设置为多少
         */
        id.set(person, 1001);
        /**
         * 获取当前属性的值
         * get():
         *      参数一：获取哪个对象的当前属性值
         */
        int pid = (int) id.get(person);
        System.out.println(pid);


    }

    /**
     * 如何操作运行时类中的指定属性---->需要掌握
     *
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        Class clazz = Person.class;
        //创建运行时类对象
        Person person = (Person) clazz.newInstance();

        //1.getDeclaredField():获取运行时类中指定的变量名的属性
        Field name = clazz.getDeclaredField("name");
        //2.保证当前属性是可以访问的
        name.setAccessible(true);
        //3.获取或设置指定对象的此属性值
        name.set(person, "Tom");
        System.out.println(name.get(person));
    }

    /**
     * 如何操作运行时类中的指定方法--->需要掌握
     *
     * @throws Exception
     */
    @Test
    public void testMethod() throws Exception {
        Class clazz = Person.class;
        //创建运行时类对象
        Person person = (Person) clazz.newInstance();
        //1.获取指定的某个方法
        /**
         * getDeclaredMethod():
         *     参数一：指明获取的方法名称
         *     参数二：指明获取方法的形参列表
         */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //2.保证当前属性是可以访问的
        show.setAccessible(true);
        /**
         * invoke():
         *      参数一：方法的调用者
         *      参数二：给方法形参赋值的实参
         * invoke()方法的返回值，即为对应类中调用方法的返回值
         */
        //3.调用方法的invoke
        // String nation = perosn.show("CHN")
        String nation = (String) show.invoke(person, "CHN");
        System.out.println(nation);

        System.out.println("=====================如何调用静态方法====================");
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用的运行时类中的方法没有返回值，则此invoke()返回null
        Object returnValue = showDesc.invoke(Person.class);
        // Object returnValue = showDesc.invoke(null);
        System.out.println(returnValue);
    }

    /**
     * 如何调用运行时类中指定的构造器
     */
    @Test
    public void testConstructor() throws Exception {
        Class clazz = Person.class;
        /*
         * 1.获取指定的构造器
         * getDeclaredConstructor()：参数：指明构造器的参数列表
         */
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        //2.保证此构造器是可以访问的
        constructor.setAccessible(true);
        //3.调用此构造器创建运行时类对象
        Person person = (Person) constructor.newInstance("Tom");
        System.out.println(person);
    }
}
